Revert "html update"
[clinton/website/site/unknownlamer.org.git] / Metaobject Protocols.html
CommitLineData
2aff8b5c 1<?xml version="1.0" encoding="utf-8" ?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml">
5 <head>
6 <title>Metaobject Protocols</title>
7 <meta name="generator" content="muse.el" />
8 <meta http-equiv="Content-Type"
9 content="text/html; charset=utf-8" />
11f9bd69
CE
10 <meta name="viewport"
11 content="width=device-width, initial-scale=1.0" />
98266870 12 <link href="https://feeds.unknownlamer.org/rss/site-updates"
a7e21d41 13 rel="alternate" type="application/rss+xml" title="Updates Feed" />
14
7404d4e1 15<link rel="stylesheet" href="default.css" />
2aff8b5c 16 </head>
17 <body>
18 <h1>Metaobject Protocols</h1>
19 <div class="contents">
20<dl>
21<dt>
22<a href="#sec1">Background</a>
23</dt>
24<dd>
25<dl>
26<dt>
27<a href="#sec2">Object Protocols</a>
28</dt>
29<dt>
30<a href="#sec3">CLOS Way of OO</a>
31</dt>
32<dd>
33<dl>
34<dt>
a7e21d41 35<a href="#sec4">Classes for Scratch Data and Types</a>
2aff8b5c 36</dt>
37<dt>
a7e21d41 38<a href="#sec5">Generics with Methods that Implement Protocols</a>
2aff8b5c 39</dt>
40</dl>
41</dd>
42</dl>
43</dd>
44<dt>
45<a href="#sec6">Limitations of Default Language Behavior</a>
46</dt>
47<dd>
48<dl>
49<dt>
50<a href="#sec7">Slot Storage</a>
51</dt>
52<dt>
53<a href="#sec8">Design Patterns</a>
54</dt>
55</dl>
56</dd>
57<dt>
58<a href="#sec9">Metasoftware</a>
59</dt>
60<dd>
61<dl>
62<dt>
63<a href="#sec10">Runtime Generated Classes</a>
64</dt>
65<dt>
66<a href="#sec11">Object Inspection</a>
67</dt>
68</dl>
69</dd>
70<dt>
71<a href="#sec12">Metaobject Protocols</a>
72</dt>
73<dd>
74<dl>
75<dt>
76<a href="#sec13">Limited/Generalized Internals of the Implementation</a>
77</dt>
78<dt>
79<a href="#sec14">Classes of MOPs</a>
80</dt>
81<dd>
82<dl>
83<dt>
84<a href="#sec15">Reflective</a>
85</dt>
86<dt>
87<a href="#sec16">Intercessory</a>
88</dt>
89</dl>
90</dd>
91<dt>
92<a href="#sec17">Violation of Encapsulation?</a>
93</dt>
94</dl>
95</dd>
96<dt>
97<a href="#sec18">MOP Design Principles</a>
98</dt>
99<dd>
100<dl>
101<dt>
102<a href="#sec19">Layered Protocol</a>
103</dt>
104<dd>
105<dl>
106<dt>
a7e21d41 107<a href="#sec20">Top Level <strong>Must</strong> Call Lower Level Methods</a>
2aff8b5c 108</dt>
109<dt>
a7e21d41 110<a href="#sec21">Lower Level Methods are Easier to Customize</a>
2aff8b5c 111</dt>
112</dl>
113</dd>
114<dt>
115<a href="#sec22">Functional Where Possible</a>
116</dt>
117<dd>
118<dl>
119<dt>
120<a href="#sec23">Memoization</a>
121</dt>
122<dt>
a7e21d41 123<a href="#sec24">Constant Shared Return Values</a>
2aff8b5c 124</dt>
125</dl>
126</dd>
127<dt>
36fbff92 128<a href="#sec25">Procedural Only Where Necessary</a>
2aff8b5c 129</dt>
2aff8b5c 130<dt>
a7e21d41 131<a href="#sec26">Real World</a>
2aff8b5c 132</dt>
133<dd>
134<dl>
135<dt>
a7e21d41 136<a href="#sec27">UCW and Arnesi</a>
2aff8b5c 137</dt>
138<dt>
a7e21d41 139<a href="#sec28">CLSQL</a>
2aff8b5c 140</dt>
141<dt>
a7e21d41 142<a href="#sec29">Elephant</a>
2aff8b5c 143</dt>
144</dl>
145</dd>
146</dl>
147</dd>
148<dt>
36fbff92 149<a href="#sec30">Sources and Further Reading</a>
2aff8b5c 150</dt>
151<dd>
152<dl>
153<dt>
a7e21d41 154<a href="#sec31">Sources</a>
2aff8b5c 155</dt>
156<dd>
157<dl>
158<dt>
a7e21d41 159<a href="#sec32">The Art of the Metaobject Protocol</a>
2aff8b5c 160</dt>
161<dt>
a7e21d41 162<a href="#sec33">CLOS MOP Specification</a>
2aff8b5c 163</dt>
164<dt>
a7e21d41 165<a href="#sec34">Metaobject Protocols: Why We Want Them and What Else They Can Do</a>
2aff8b5c 166</dt>
167<dt>
a7e21d41 168<a href="#sec35">Why Are Black Boxes so Hard to Reuse?</a>
2aff8b5c 169</dt>
170</dl>
171</dd>
172<dt>
a7e21d41 173<a href="#sec36">Further Reading</a>
2aff8b5c 174</dt>
175<dd>
176<dl>
177<dt>
a7e21d41 178<a href="#sec37">A Metaobject Protocol for C++</a>
2aff8b5c 179</dt>
180<dt>
a7e21d41 181<a href="#sec38">Open Implementations and Metaobject Protocols</a>
2aff8b5c 182</dt>
183</dl>
184</dd>
36fbff92 185<dt>
186<a href="#sec39">Software</a>
187</dt>
188<dd>
189<dl>
190<dt>
191<a href="#sec40">Closer to MOP</a>
192</dt>
193</dl>
194</dd>
2aff8b5c 195</dl>
196</dd>
197</dl>
198</div>
199
200
11f9bd69
CE
201<!-- Page published by Emacs Muse begins here -->
202<p>In Fall of 2006 I did a small project on Metaobject Protocols for my
2aff8b5c 203CS 331 class. Here lie my notes which may perhaps be useful to
204others. I hope to expand them into something more useful over time.</p>
205
206<h2><a name="sec1" id="sec1"></a>
207Background</h2>
208
209<h3><a name="sec2" id="sec2"></a>
210Object Protocols</h3>
211
212<p class="first">An object protocol is a set of methods and specification of the
213interactions between the methods which provide some generic behavior
214(e.g. of a sequence) that are then implemented by classes which
215conform to the protocol (e.g. a vector or list). In most object
216systems a class contains both the methods which implement a protocol
217and the data used by the implementation. The intent is to emulate
218state machines which pass messages between each other.</p>
219
220
221<h3><a name="sec3" id="sec3"></a>
222CLOS Way of OO</h3>
223
224<p class="first">The Common Lisp Object System (CLOS) is different. It separates
225the data and method concepts into classes and generics. A class
226contains data fields only, and a generic has methods specialized for
227certain types attached to it. This seems a bit weird at first, but is
228significantly more powerful as it encourages complete encapsulation
229through its use of classes primarily for method specialization rather
230than for state storage.</p>
231
2aff8b5c 232<h4><a name="sec4" id="sec4"></a>
a7e21d41 233Classes for Scratch Data and Types</h4>
2aff8b5c 234
235<p class="first">In CLOS classes store data in slots (which are the same as data
236members). Encapsulation is not provided; any bit of code can use
237<code>slot-value</code> to access or set the value of a slot. This may seem odd at
238first, but encapsulation is of questionable importance as the slots
239are meant only to be used by the protocol defined around the class.</p>
240
a7e21d41 241<p>Classes are defined with <code>defclass</code></p>
2aff8b5c 242
243<pre class="src">
7404d4e1 244(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">name</span> (superclasses ...)
245 ((slot-name <span class="emacs-face-builtin">:accessor</span> slot-accessor ...)
2aff8b5c 246 ...)
247 (class-options ...))
248
7404d4e1 249(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">example</span> ()
250 ((foo <span class="emacs-face-builtin">:accessor</span> foo-of <span class="emacs-face-builtin">:initform</span> 5)))
2aff8b5c 251
7404d4e1 252(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">example-child</span> (example)
253 ((bar <span class="emacs-face-builtin">:accessor</span> bar-of <span class="emacs-face-builtin">:initform</span> (list 1 2 3))))
2aff8b5c 254</pre>
255
36fbff92 256<p>Slot definitions have several options; the above example shows only the
2aff8b5c 257<code>:accessor</code> and <code>:initform</code> options which are the most commonly
258used. <code>:accessor</code> generates an accessor for the slot (e.g. if you have
a7e21d41 259an instance of <code>example</code> you can <code>(setf (foo-of some-example-instance)
260'some-value)</code> to set and <code>(foo-of some-example-instance)</code> to access the
2aff8b5c 261value). <code>:initform</code> provides a default initial value for the slot as a
a7e21d41 262symbolic expression to be evaluated when an instance is created in the
263lexical environment of the class definition.</p>
2aff8b5c 264
265
266<h4><a name="sec5" id="sec5"></a>
a7e21d41 267Generics with Methods that Implement Protocols</h4>
2aff8b5c 268
269<p class="first">Generics are like normal functions in Lisp, but they only provide a
270lambda list (parameter list). Methods are added to the generic which
a7e21d41 271specialize on the types of their parameters and provide an
272implementation. This allows writing rich layered protocols which can
273enable selective modification of individual facets with minimal code.</p>
2aff8b5c 274
275<pre class="src">
7404d4e1 276(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">generic</span> (parameters ...)
2aff8b5c 277 (options) ...)
278
7404d4e1 279(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">generic-name</span> ((parameter type) parameter ...)
4222507d 280 <span class="emacs-face-doc">"documentation string"</span>
2aff8b5c 281 body)
282
7404d4e1 283(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">foo</span> (bar baz quux)
4222507d 284 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Process the baz with the quux capacitor to make the
2aff8b5c 285foo widget fly into the sky at warp speed"</span>))
286
7404d4e1 287(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">foo</span> ((bar example) baz (quux capacitor))
2aff8b5c 288 (launch bar (process-with quux baz)))
289</pre>
290
291<p>A method lambda list differs from a normal lambda list only in that it
292can specify the type of the parameter using the notation <code>(name type)</code>.
293Note also that methods can specialize on the types of every
294argument and not just the first one. This is quite powerful for
295reasons outside of the scope of this presentation.</p>
296
297
298
299
300<h2><a name="sec6" id="sec6"></a>
301Limitations of Default Language Behavior</h2>
302
303<p class="first">The behavior of a language is a compromise between many competing
a7e21d41 304issues that attempts to be as generally useful as possible so that
305<em>most</em> applications will have no issue with the default behavior. There
306are, however, certain applications that could be cleanly written with
307minor modifications to the behavior of the language, but would be
308impossible or quite difficult to write otherwise.</p>
2aff8b5c 309
310<h3><a name="sec7" id="sec7"></a>
311Slot Storage</h3>
312
313<p class="first">Most languages choose to preallocate storage for all of the slots of
a7e21d41 314an instance. Now imagine a contact database that stores information
315about people in slots of a class. There may be dozens of slots, but
316often many of them will be left blank. If slot storage is preallocated
317much memory will be wasted and the database may not be able to fit
318into the memory of the hardware it must run on (perhaps for financial
319reasons, huge datasets, etc.).</p>
2aff8b5c 320
321<p>To save memory the author of the contact database must implement his
322own system to store properties and allocate them lazily. This
323represents a fair bit of effort, and would implement a system that
a7e21d41 324differed from the existing slot system of classes only regarding slot
325storage.</p>
2aff8b5c 326
a7e21d41 327<p>It would be useful if there were a way to customize slot allocation in
328instances. The customizations would be minor and require overriding
2aff8b5c 329only the initial allocation behavior and the behavior of the first
330assignment to the slot. It is a a trivial problem in a language that
a7e21d41 331allows customization of these behaviors.</p>
2aff8b5c 332
333
334<h3><a name="sec8" id="sec8"></a>
335Design Patterns</h3>
336
337<p class="first">Design Patterns are generalized versions of common patterns found in
338programs. Many of them are merely methods to get around deficiencies
339in the language, and can be quite messy to implement in some
a7e21d41 340languages. Ideally a pattern would be subsumed by the language, but
36fbff92 341real world constraints require language standards to remain fairly
a7e21d41 342static.</p>
2aff8b5c 343
344
345
346<h2><a name="sec9" id="sec9"></a>
347Metasoftware</h2>
348
349<p class="first">Some types of programs could be written easily if the language were
a7e21d41 350customizable but are nearly impossible to write when it is not.</p>
2aff8b5c 351
352<h3><a name="sec10" id="sec10"></a>
353Runtime Generated Classes</h3>
354
355<p class="first">Say you wanted to write a video game where players could create their
356own objects, attach behaviors to the objects, and perhaps mix
357different objects together to create new ones. When you abstract the
358problem this looks just like an object system! Wouldn't it be nice if
a7e21d41 359your program could create new classes and methods on the fly portably?</p>
2aff8b5c 360
361
362<h3><a name="sec11" id="sec11"></a>
363Object Inspection</h3>
364
a7e21d41 365<p class="first">Imagine you were developing a complicated program with many different
366objects that interacted in fairly complex ways. A tool to inspect the
367structure of objects while debugging would be quite useful, but in a
368traditional language would be impossible to implement portably. This
369could force you to purchase a certain compiler implementation which
370provided an inspector, and even then would likely not be customizable.</p>
2aff8b5c 371
372<p>This problem can be generalized to apply to most debugging tools; it
373would be useful to write such tools portably because users of the
374<em>language</em> and not the <em>compiler</em> need to debug software. Sharing
375infrastructure would result in better tools (more developers), and
a7e21d41 376save the man-years of wasted effort that comes with having to rewrite
377unportable tools from scratch multiple times.</p>
2aff8b5c 378
379
380
381<h2><a name="sec12" id="sec12"></a>
382Metaobject Protocols</h2>
383
384<h3><a name="sec13" id="sec13"></a>
385Limited/Generalized Internals of the Implementation</h3>
386
a7e21d41 387<p class="first">A Metaobject Protocol (MOP) is a generalized and limited subset of the
388underlying language implementation. It is limited to allow multiple
389implementation strategies; this, along with careful design, is
390essential because programming language research is ever advancing and
391new techniques for creating more reliable and faster implementations
392are still being discovered.</p>
2aff8b5c 393
394<p>This subset of the implementation is exported as a set of methods on
a7e21d41 395metaobjects. Thus the language is implemented in itself. The system
396can then be customized using the extension and overriding features of
397the language itself.</p>
2aff8b5c 398
399
400<h3><a name="sec14" id="sec14"></a>
401Classes of MOPs</h3>
402
403<h4><a name="sec15" id="sec15"></a>
404Reflective</h4>
405
a7e21d41 406<p class="first">A reflective MOP provides an interface to information <em>about</em> the
407running system. It exposes class relationships, the methods attached
408to a generic, etc. A reflective MOP often provides some functionality
409for creating new classes at runtime. Smalltalk was one of the first
410languages to expose a reflective MOP.</p>
2aff8b5c 411
412<h5>Example: Object Inspector</h5>
413
2aff8b5c 414<pre class="src">
7404d4e1 415(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">example-inspect</span> (instance)
4222507d 416 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Simple object inspector using CLOS MOP"</span>))
2aff8b5c 417
7404d4e1 418(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">example-inspect</span> ((instance t))
419 (format t <span class="emacs-face-string">"Simple Object~% Value: ~S~%"</span> instance))
2aff8b5c 420
7404d4e1 421(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">example-inspect</span> ((instance standard-object))
422 (<span class="emacs-face-keyword">let</span> ((class (class-of instance)))
423 (format t <span class="emacs-face-string">"Class: ~S, Superclasses: ~S~%"</span>
2aff8b5c 424 (class-name class)
425 (mapcar #'class-name
426 (class-precedence-list class)))
7404d4e1 427 (<span class="emacs-face-keyword">let</span> ((slot-names (mapcar #'slot-definition-name
2aff8b5c 428 (class-slots class))))
7404d4e1 429 (format t <span class="emacs-face-string">"Slots: ~%~{ ~S~%~}"</span> slot-names)
2aff8b5c 430 (inspect-loop slot-names instance #'example-inspect))))
431
7404d4e1 432(<span class="emacs-face-keyword">defun</span> <span class="emacs-face-function-name">inspect-loop</span> (slots instance inspector)
433 (format t <span class="emacs-face-string">"Enter slot to inspect or :pop to go up one level: "</span>)
2aff8b5c 434 (finish-output)
7404d4e1 435 (<span class="emacs-face-keyword">let*</span> ((slot (read))
2aff8b5c 436 (found-slot (member slot slots)))
7404d4e1 437 (<span class="emacs-face-keyword">cond</span> (found-slot
2aff8b5c 438 (funcall inspector (slot-value instance slot))
439 (funcall inspector instance))
7404d4e1 440 ((eq slot <span class="emacs-face-builtin">:pop</span>) t)
2aff8b5c 441 (t
7404d4e1 442 (format t <span class="emacs-face-string">"~S is invalid. Valid slot names: ~S~%"</span>
2aff8b5c 443 slot
444 slots)
445 (inspect-loop slots instance inspector)))))
446</pre>
447
448
a7e21d41 449<h5>Example: Runtime Generated Classes and Methods</h5>
450
451
452
453<h4><a name="sec16" id="sec16"></a>
454Intercessory</h4>
455
456<p class="first">Intercessory MOPs allow the user to customize language behavior by
457implementing methods which override certain aspects of the language
458behavior. This class of MOPs are what make MOPs especially
459powerful. No longer must a problem be restructured to fit the
36fbff92 460implementation language; the underlying language can be reshaped to
a7e21d41 461fit the task at hand, and obfuscation of the intended structure of the
462application can be avoided.</p>
463
464<h5>Example: Lazily Allocated Slots</h5>
465
466
467<h5>Example: Observer Design Pattern</h5>
2aff8b5c 468
a7e21d41 469<p>A simple implementation of the observer pattern is under 100 lines,
2aff8b5c 470and the user level code requires only a single line of code to make
471any existing class observable.</p>
472
473<p>In a language lacking a MOP, implementing the observer pattern
474requires modifying every accessor of a class to explicitly invoke any
36fbff92 475observers, and necessitates the addition of a mixin class to the class
476hierarchy. The fact that an object can be observed is a meta property
2aff8b5c 477of the class, and forcing it to be implemented at the application
36fbff92 478level dirties the inheritance hierarchy and adds unnecessary meta
2aff8b5c 479details to the program.</p>
480
481<pre class="src">
7404d4e1 482<span class="emacs-face-comment-delimiter">;;; </span><span class="emacs-face-comment">This metaclass adds a slot to instances which use it, and so the
483</span><span class="emacs-face-comment-delimiter">;;; </span><span class="emacs-face-comment">system is defined in its own package to avoid name conflicts
484</span>(<span class="emacs-face-keyword">defpackage</span> <span class="emacs-face-type">:observer</span>
36fbff92 485 (<span class="emacs-face-builtin">:use</span> <span class="emacs-face-builtin">:cl</span> <span class="emacs-face-builtin">:c2mop</span>)
7404d4e1 486 (<span class="emacs-face-builtin">:export</span> observable register-observer unregister-observer))
2aff8b5c 487
7404d4e1 488(<span class="emacs-face-keyword">in-package</span> <span class="emacs-face-builtin">:observer</span>)
2aff8b5c 489
7404d4e1 490<span class="emacs-face-comment-delimiter">;;; </span><span class="emacs-face-comment">Metaclass
491</span>(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">observable</span> (standard-class)
2aff8b5c 492 ()
4222507d 493 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Metaclass for observable objects"</span>))
2aff8b5c 494
7404d4e1 495(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">compute-slots</span> ((class observable))
4222507d 496 <span class="emacs-face-doc">"Add a slot for storing observers to observable instances"</span>
2aff8b5c 497 (cons (make-instance 'standard-effective-slot-definition
7404d4e1 498 <span class="emacs-face-builtin">:name</span> 'observers
499 <span class="emacs-face-builtin">:initform</span> '(make-hash-table)
500 <span class="emacs-face-builtin">:initfunction</span> #'(<span class="emacs-face-keyword">lambda</span> () (make-hash-table)))
2aff8b5c 501 (call-next-method)))
502
7404d4e1 503(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">validate-superclass</span> ((class observable)
2aff8b5c 504 (super standard-class))
505 t)
506
7404d4e1 507(<span class="emacs-face-keyword">defun</span> <span class="emacs-face-function-name">register-observer</span> (instance slot-name key closure)
2aff8b5c 508 (register-observer-with-class (class-of instance)
509 instance
510 slot-name
511 key
512 closure))
513
7404d4e1 514(<span class="emacs-face-keyword">defun</span> <span class="emacs-face-function-name">unregister-observer</span> (instance slot-name key)
2aff8b5c 515 (unregister-observer-with-class (class-of instance)
516 instance
517 slot-name
518 key))
519
7404d4e1 520(<span class="emacs-face-keyword">defun</span> <span class="emacs-face-function-name">get-observers</span> (instance slot-name)
2aff8b5c 521 (get-observers-with-class (class-of instance)
522 instance
523 slot-name))
524
7404d4e1 525(<span class="emacs-face-keyword">defun</span> <span class="emacs-face-function-name">add-observer-table</span> (instance slot-name)
2aff8b5c 526 (setf (gethash slot-name (slot-value instance
527 'observers))
528 (make-hash-table)))
529
7404d4e1 530(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">register-observer-with-class</span> (class instance slot-name key closure))
531(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">unregister-observer-with-class</span> (class
2aff8b5c 532 instance
533 slot-name
534 key))
535
7404d4e1 536(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">register-observer-with-class</span> ((class observable)
2aff8b5c 537 instance
538 slot-name
539 key
540 closure)
541 (setf (gethash key
542 (or (gethash slot-name
543 (slot-value instance 'observers))
7404d4e1 544 <span class="emacs-face-comment-delimiter">;; </span><span class="emacs-face-comment">Lazily add observer hash tables
2aff8b5c 545</span> (add-observer-table instance slot-name)))
546 closure))
547
7404d4e1 548(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">unregister-observer-with-class</span> ((class observable)
2aff8b5c 549 instance
550 slot-name
551 key)
552 (remhash key (gethash slot-name
553 (slot-value instance 'observers))))
554
7404d4e1 555(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">get-observers-with-class</span> ((class observable)
2aff8b5c 556 instance
557 slot-name)
558 (gethash slot-name (slot-value instance 'observers)))
559
4222507d 560(<span class="emacs-face-keyword">defmethod</span> (<span class="emacs-face-function-name">setf slot-value-using-class</span>) <span class="emacs-face-builtin">:before</span> (new-value
2aff8b5c 561 (class observable)
562 instance
563 slot)
7404d4e1 564 (<span class="emacs-face-keyword">let</span> ((slot-name (slot-definition-name slot)))
565 (<span class="emacs-face-keyword">if</span> (not (eq 'observers slot-name))
566 (<span class="emacs-face-keyword">let</span> ((observers
2aff8b5c 567 (get-observers instance (slot-definition-name slot))))
7404d4e1 568 (<span class="emacs-face-keyword">if</span> observers
569 (maphash #'(<span class="emacs-face-keyword">lambda</span> (key observer)
2aff8b5c 570 (funcall observer
7404d4e1 571 (<span class="emacs-face-keyword">if</span> (slot-boundp instance slot-name)
2aff8b5c 572 (slot-value instance slot-name)
573 nil)
574 new-value))
575 observers))))))
576</pre>
577
578
a7e21d41 579
580
581
582<h3><a name="sec17" id="sec17"></a>
583Violation of Encapsulation?</h3>
584
585<p class="first">A MOP may seem like a violation of encapsulation by revealing some
586implementation details, but in reality a well designed protocol does
587not reveal anything which was not already exposed. Implementation
588decisions affect users, and some of these details do leak through to
589higher levels (e.g. the memory layout of slots). Implicit in the
590protocol specification are these implementation details, and the MOP
591merely makes this limited subset available for customization.</p>
592
593<p>A MOP makes it possible to customize certain implementation decisions
594that do not <strong>radically</strong> alter the behavior of the base language. The
595conceptual vocabulary of the system retains its meaning, and so code
596written in one dialect can interact with code written in another
597without knowing that they speak different ones.</p>
598
599
600
601<h2><a name="sec18" id="sec18"></a>
602MOP Design Principles</h2>
603
604<h3><a name="sec19" id="sec19"></a>
605Layered Protocol</h3>
606
607<p class="first">A layered protocol design is good for both meta and normal object
608protocols, and enables a combinatorial explosion of customizations to
609the protocol.</p>
610
611<h4><a name="sec20" id="sec20"></a>
612Top Level <strong>Must</strong> Call Lower Level Methods</h4>
613
614<p class="first">The top level methods of a layered protocol are required to call
615certain lower level methods to perform some tasks. This both makes it
616easier to customize the top level methods (which perform very broad
617tasks) by providing some pieces of implementation for the programmer,
618and enables more customization by opening up the replacement of lower
619level functions as a way to alter a small detail of the high level
620behavior.</p>
621
622
623<h4><a name="sec21" id="sec21"></a>
624Lower Level Methods are Easier to Customize</h4>
625
626<p class="first">The lower level methods of a MOP are limited in scope and can be
627implemented easily. Often the desired changes to language behavior are
628minor, and having methods that perform simple tasks which are often
629customized reduces the effort required to extend the system.</p>
630
631
632
633<h3><a name="sec22" id="sec22"></a>
634Functional Where Possible</h3>
635
636<p class="first">Functional protocols are preferred for MOPs (and object protocols in
637general). Functional protocols open up several optimizations for the
638implementation without burdening the user of the protocol.</p>
639
640<h4><a name="sec23" id="sec23"></a>
641Memoization</h4>
642
643<p class="first">Memoization is the process of saving the results of a function call
644for future use. This avoids expensive recomputation of values which
645have not changed (recall that a true function will always return the
646same result when given the same arguments).</p>
647
648<p>A functional MOP can be optimized easily by exploiting this property
649to memoize the return values of calls to expensive operations. A MOP
650must be be very fast to avoid making programs unusably slow, and
651memoization is able to give an appreciable speedup in many cases
652without a significant burden on memory usage.</p>
653
654
655<h4><a name="sec24" id="sec24"></a>
656Constant Shared Return Values</h4>
657
658<p class="first">Disallowing modification of values returned by protocol methods allows
659the implementation to return large data structures by reference to
660avoid expensive copying without having to do expensive data integrity
661checks or copying.</p>
662
663
664
665<h3><a name="sec25" id="sec25"></a>
36fbff92 666Procedural Only Where Necessary</h3>
a7e21d41 667
36fbff92 668<p class="first">Some operations like method invocation are inherently stateful and so
a7e21d41 669must use a procedural protocol. There is no benefit to be gained from
670using a functional protocol, and indeed an attempt would result in
36fbff92 671obtuse code that severely restricted the implementation. Do note that
a7e21d41 672only a very small part of method invocation is stateful (the actual
673call), and most of it can be implemented functionally (e.g. computing
674the discriminating function).</p>
675
676
677<h3><a name="sec26" id="sec26"></a>
2aff8b5c 678Real World</h3>
679
a7e21d41 680<h4><a name="sec27" id="sec27"></a>
2aff8b5c 681<a href="http://common-lisp.net/project/ucw/">UCW</a> and <a href="http://common-lisp.net/project/bese/arnesi.html">Arnesi</a></h4>
682
36fbff92 683<p class="first">Arnesi uses the CLOS MOP to implement methods which are transparently
2aff8b5c 684rewritten into continuation passing style. This allows their execution
685to be suspended at certain points and resumed later. UCW builds on top
686of this to support a web framework where the statelessness of http is
687hidden from the user; displaying a page suspends the execution of the
688current continuation, and resumes it upon submission. The user level
689code is completely unaware of this.</p>
690
691
a7e21d41 692<h4><a name="sec28" id="sec28"></a>
2aff8b5c 693<a href="http://clsql.b9.com">CLSQL</a></h4>
694
695<p class="first">CLSQL uses the reflective part of the CLOS MOP to map Common Lisp data
696types into SQL types, and the intercessory protocol for slot
697allocation to map slots onto database columns or sql expressions (for
698implementing relational slots).</p>
699
700
a7e21d41 701<h4><a name="sec29" id="sec29"></a>
2aff8b5c 702<a href="http://common-lisp.net/project/elephant/">Elephant</a></h4>
703
36fbff92 704<p class="first">Elephant uses the CLOS MOP to transparently store any class to disk
a7e21d41 705and handle paging between the disk store and memory efficiently
706without user intervention.</p>
2aff8b5c 707
708
709
710
a7e21d41 711<h2><a name="sec30" id="sec30"></a>
36fbff92 712Sources and Further Reading</h2>
2aff8b5c 713
a7e21d41 714<h3><a name="sec31" id="sec31"></a>
2aff8b5c 715Sources</h3>
716
a7e21d41 717<h4><a name="sec32" id="sec32"></a>
2aff8b5c 718The Art of the Metaobject Protocol</h4>
719
720<h5>Kiczales, Gregor et al. MIT Press 1991</h5>
721
722<p>Highly recommended reading even if you plan to never implement a MOP
723or use the CLOS one. The design principles it recommends are quite
724useful.</p>
725
726
727
a7e21d41 728<h4><a name="sec33" id="sec33"></a>
2aff8b5c 729<a href="http://www.lisp.org/mop/contents.html">CLOS MOP Specification</a></h4>
730
731<p class="first">Specification of the MOP for CLOS defined in <em>The Art of the Metaobject Protocol</em>.</p>
732
733
a7e21d41 734<h4><a name="sec34" id="sec34"></a>
2aff8b5c 735<a href="http://citeseer.ist.psu.edu/399658.html">Metaobject Protocols: Why We Want Them and What Else They Can Do</a></h4>
736
737<p class="first">A short overview of MOP design principles followed by three example
738metaobject protocols for Scheme.</p>
739
740
a7e21d41 741<h4><a name="sec35" id="sec35"></a>
2aff8b5c 742<a href="http://www2.parc.com/csl/groups/sda/projects/oi/towards-talk/transcript.html">Why Are Black Boxes so Hard to Reuse?</a></h4>
743
744<p class="first">Transcription of a talk on the benefits of open implementations of
745software. It first discusses several problems that black box software
746implementations pose, and then presents existing solutions. It shows
747how the existing solutions are insufficient, and then provides
748metaobject protocols as a solution to most of the problems.</p>
749
750
751
a7e21d41 752<h3><a name="sec36" id="sec36"></a>
2aff8b5c 753Further Reading</h3>
754
a7e21d41 755<h4><a name="sec37" id="sec37"></a>
2aff8b5c 756<a href="http://citeseer.ist.psu.edu/chiba95metaobject.html">A Metaobject Protocol for C++</a></h4>
757
758<p class="first">Example of a purely compile time MOP. It implements the functionality
759of a code walker and something similar to the Lisp macro system.</p>
760
761
a7e21d41 762<h4><a name="sec38" id="sec38"></a>
2aff8b5c 763<a href="http://www.parc.com/csl/groups/sda/publications/papers/Kiczales-TUT95/for-web.pdf">Open Implementations and Metaobject Protocols</a></h4>
764
765<p class="first">It is a bit long, but it seems to follow a similar structure to AMOP
766in introducing MOPs and their usefulness. The pages are slides with
767notes, and so the 331 pages might not actually take that long to read.</p>
768
769
770
36fbff92 771<h3><a name="sec39" id="sec39"></a>
772Software</h3>
773
774<h4><a name="sec40" id="sec40"></a>
775<a href="http://common-lisp.net/project/closer/closer-mop.html">Closer to MOP</a></h4>
776
777<p class="first">Compatibility layer that attempts to present the <em>Art of the Metaobject
778Protocol</em> MOP specification properly in as many Common Lisp
779implementation as possible.</p>
780
781
782
2aff8b5c 783
784 <!-- Page published by Emacs Muse ends here -->
785
786 <p class="cke-buttons">
787 <!-- validating badges, any browser, etc -->
98266870
CE
788 <a href="https://validator.w3.org/check/referer"><img
789 src="https://www.w3.org/Icons/valid-xhtml10"
2aff8b5c 790 alt="Valid XHTML 1.0!" /></a>
791
98266870 792 <a href="https://www.anybrowser.org/campaign/"><img
2aff8b5c 793 src="img/buttons/w3c_ab.png" alt="[ Viewable With Any Browser
794 ]" /></a>
795
98266870 796 <a href="https://www.debian.org/"><img
2aff8b5c 797 src="img/buttons/debian.png" alt="[ Powered by Debian ]" /></a>
798
98266870 799 <a href="https://hcoop.net/">
2aff8b5c 800 <img src="img/buttons/hcoop.png"
801 alt="[ Hosted by HCoop]" />
802 </a>
803
98266870 804 <a href="https://www.fsf.org/register_form?referrer=114">
2aff8b5c 805 <img src="img/buttons/fsf_member.png"
806 alt="[ FSF Associate Member ]" />
807 </a>
808 </p>
809
11f9bd69
CE
810<p class="cke-footer">&lt;ascii_phil&gt; There once was a man named Bertold
811&lt;ascii_phil&gt; Who drank beer when the weather grew cold
812&lt;ascii_phil&gt; As he reached for his cup...
813&lt;ascii_phil&gt; "NEEEEVER GONNA GIVE YOU UP!!!"
814&lt;ascii_phil&gt; Oh, snap! You just got limerickrolled!
2aff8b5c 815</p>
816<p class="cke-timestamp">Last Modified:
f6d19803 817 January 21, 2013</p>
2aff8b5c 818 </body>
819</html>